/**
 java反射机制是在运行状态中，对于任意一个类，都能知道这个类的所有属性和方法;对于任意一个对象，能够调用它的任意
 一个方法和属性，这种动态获取的信息以及动态调用对象方法的功能称为反射
 反射-Reflection
 类信息 ---->>对象
 对象------->>类信息
 Class类是一切的反射根源。
 Class类表示什么？
 很多的人--可以定义一个Person类（有年纪，性别，姓名等）
 很多的车--可以定义一个Car类（有发动机，颜色，车轮等）
 很多的类--Class类（类名，构造方法，属性，方法）
 得到Class类的对象有三种方法：
 1.Obeject类中的getClass（）方法
 2.类.class
 3.Class类的forName方法

 使用Class类进行对象的实例化操作
 调用无参构造进行实例化
    public T newInstance() throws Instantiation Exception,IllegalAccessException
 调用有参构造进行实例化
    public Constructor<?>[]getConstructors() throws SecurityException
 */
package 第十二章_反射与内省;

import org.junit.Test;
import sun.security.util.Length;

import java.lang.reflect.*;
import java.text.DecimalFormat;
import java.util.Arrays;

public class 第十二章_反射的定义 {
    @Test
    public void Class_3种实例化(){
        //通过Object的getclass  来反射  情况：知道对象名
        Cat cat=new Cat();
        Dog dog=new Dog("mm",2,"white",cat);

        Class aClass = dog.getClass();

        //通过.class 来反射  情况：只知道类名
        Class dogClass = Dog.class;

        //通过Class.forName 来反射  情况：只知道文件位置
        try {
            Class aClass1=Class.forName("第十二章_反射与内省.Dog");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    @Test
    public void ClassToclass(){
        try {
            Class aClass1=Class.forName("第十二章_反射与内省.Dog");
            //Dog dog= (Dog) aClass1.newInstance();
            //利用Class类 读取 构造器 字段 和 方法
            Constructor[] constructors = aClass1.getConstructors();
            Field[] fields = aClass1.getDeclaredFields();
            final Method[] methods = aClass1.getMethods();
            int length = constructors.length;

            for(int i =0;i<length;i++){
                System.out.println("parameter count: "+constructors[i].getParameterCount());
            }
            length=fields.length;
            System.out.println("===declaredFields（声明的字段）===");
            for(int i=0;i<length;i++){
                System.out.println("-------");
                System.out.println("fields: "+fields[i]);
            }
            length=methods.length;
            System.out.println("======method(方法)=======");
            for(int i=0;i<length;i++){
                System.out.println("----method----");
                System.out.println("method: "+methods[i]);
            }

            } catch (ClassNotFoundException ex) {
            throw new RuntimeException(ex);
        }
    }
    @Test
    public void newInstance(){
        Cat cat=new Cat();
        //生产Class 容器 的Dog类 的 容对象
        final Class<Dog> dogClass = Dog.class;
        //构造 容器 的 构造数组对象
        final Constructor<?>[] constructors = dogClass.getConstructors();
        //字段的 对象
        final Field[] declaredFields = dogClass.getDeclaredFields();
        //方法的 对象
        final Method[] declaredMethods = dogClass.getDeclaredMethods();
        int length=constructors.length;
        System.out.println("----第一步 反射出类的构造器的对象编号和数量----");
        for(int i=0;i<length;i++){
            System.out.println("构造器: "+constructors[i].getParameterTypes()+"参数数量: "+constructors[i].getParameterCount());
        }
        length=declaredFields.length;
        System.out.println("----第二步 反射出类的字段和类型-----");
        for(int i=0;i<length;i++){
            System.out.println("声明字段: "+declaredFields[i].getName()+"\n类型: "+declaredFields[i].getType());
        }
        System.out.println("-----查询构造器参数的类型------");
        Arrays.stream(constructors[2].getParameterTypes()).forEach(System.out::println);
        System.out.println("----生成一个构造器对象--------");
        try {
            //构造一个构造器
            final Constructor<Dog> constructor = dogClass.getConstructor(String.class, int.class, String.class, Cat.class);
            System.out.println("-------newInstance----生产一个类的实例化对象");
            //生成一个类 的对象
            final Dog dog = constructor.newInstance("小黑", 2, "black", cat);
            Dog dog1=new Dog("qq",3,"black",cat);
            Dog dog2=new Dog();
            for(int i=0;i<length;i++) {
                int modifiers = declaredFields[i].getModifiers();
                System.out.println("modifiers(修饰符): "+Modifier.toString(modifiers)+"  "+declaredFields[i]+ length);
                if(declaredFields[i].getName().equals("name")){
                    declaredFields[i].setAccessible(true);
                    declaredFields[i].set(dogClass,"tt");
                    System.out.println("declaredFields name= "+dog.getName());
                    length=declaredMethods.length;
                    for(i=0;i<length;i++){
                        System.out.println("声明方法: "+declaredMethods[i].getName());
                        if((declaredMethods[i].getName()).equals("setName")){
                            declaredMethods[i].setAccessible(true);
                            declaredMethods[i].invoke(dog1,"name change2");
                            System.out.println("dog1: "+dog1.getName());
                        }
                    }
                    //declaredMethods[i].equals("setName");

                }
            }
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

    }
}

class Cat{

}
class Dog{
    public static String name="1";
    private int age;
    private String color;

    Cat cat;

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }

    private void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getColor() {
        return color;
    }

    public Dog() {
    }

    public Dog(int age) {
        this.age = age;
    }

    public Dog(String name, int age, String color,Cat cat) {
        this.name = name;
        this.age = age;
        this.color = color;
        this.cat=cat;
    }
}